package pl.ydp.components.mathcell.mathrecognizer.engine
{
	
	import pl.ydp.components.mathcell.mathcell.MatchReport;
	
	import pl.ydp.components.mathcell.mathrecognizer.engine.database.ShapeModelsDatabase;
	import pl.ydp.components.mathcell.mathrecognizer.geometry.MathShape;
	import pl.ydp.components.mathcell.mathrecognizer.model.ShapeModel;
	import pl.ydp.components.mathcell.mathrecognizer.model.presets.PrimitivePresets;
	
	public class Recognizer
	{
		// constructor
		
		public function Recognizer(_field_width:Number, _field_height:Number){
			
			Parameters.ParametersSetUp(_field_width, _field_height);
			PrimitivePresets.PrimitivePresetsSetUp();
			
			constructModels(ShapeModelsDatabase.MATH_BASIC);
			
		}
		
		//  ---------- PRIVATE FIELDS ---------- 
		
		private var shapeModels:Array;
		
		
		//  ---------- PUBLIC METHODS ---------- 
		
		public function recognize(points:Array, characterTypeExpected:Number):Number{
			
			var results:Array = processShapeModels(new MathShape(points), characterTypeExpected);
			
			var best:MatchReport = findBestMatch(results);
						
			return findMatchCharacterCode(best);
		}
		
		//-------------------------------------------------------------------------
		
		public function recognizeAndReport(points:Array, characterTypeExpected:Number):Report{
			
			//Debug.clearLog();
			
			var time:Number = (new Date()).time;
			
			var shape:MathShape = new MathShape(points);
			
			var time2:Number = (new Date()).time;
			
			var results:Array = processShapeModels(shape, characterTypeExpected);
			
			var names:Array = getShapeModelNames();
			
			var output:Array = new Array();
			
			for (var r:Number = 0 ; r < results.length ; r ++ ){
				output[names[r]] = results[r];
			}
			
			//trace ("processing time: " + (time2 - time).toString());
			//trace ("matching time: " + ((new Date).time - time2).toString());
						
			return new Report(findMatchCharacterCode(findBestMatch(results)), output, shape.primitives);
		}
		
		//-------------------------------------------------------------------------
		
		public function updateFieldSize(_field_width:Number, _field_height:Number):void{
			
			Parameters.ParametersSetUp(_field_width, _field_height);
			PrimitivePresets.PrimitivePresetsSetUp();
			
			constructModels(ShapeModelsDatabase.MATH_BASIC);
			
		}
		
		public function getShapeModelNames():Array{
			var names:Array = new Array();
			
			for each (var sm:ShapeModel in shapeModels){
				names.push(sm.name);
			}
			
			return names;
		}		
		
		//  ---------- PRIVATE METHODS ---------- 
		
		
		private function constructModels(modelSet:Number):void{
			
			shapeModels = ShapeModelsDatabase.getShapeModels(modelSet);
			
		}
		
		
		private function findBestMatch(input:Array):MatchReport{
			// find best match
			var max:Number = 0;
			var bestMatch:Number = -1;
			for (var i:Number = 0 ; i < input.length ; i ++ ){
				if (input[i] > max){
					max = input[i];
					bestMatch = i;
					
				}
			}
			
			
			if (bestMatch == -1){
				return new MatchReport(-1,-1);
			}	
			
			return new MatchReport(bestMatch,max);
		}
		
		
		private function findMatchCharacterCode(mr:MatchReport):Number{
			
			const MIN_MODEL_RESULT:Number = 0.74;
			
			if (mr.value >= MIN_MODEL_RESULT){
				return shapeModels[mr.model].character.code;
			}
			
			return -1;
				
		}
		
		//-------------------------------------------------------------------------
		
		public function processShapeModels(shape:MathShape, characterTypeExpected:Number):Array{
			
			if (shape.primitives.length < 1){
				return new Array;
			}
						
			var results:Array = new Array;
			
			for each (var currShape:ShapeModel in shapeModels){
				
				if (!(currShape.character.type & characterTypeExpected)/*  &&  characterTypeExpected != CharacterType.UNKNOWN */){
					results.push(0);
					continue;
				}
				
				results.push( currShape.compare(shape) );
				
			}
			
			return results;
			
		}

	}
}